3.2 多路复用与多路分解
多路复用与多路分解是传输层能够实现将网络层提供的主机到主机的传输服务拓展到进程到进程的传输服务的核心机制。前面提到过,应用层向下层传递信息的通道是 Socket,多路复用是指传输层实体从不同套接字中收集数据块,为每个数据块封装上相关的标识信息生成报文段,再将这些报文段传递给网络层;多路分解则指的是依据收到的报文首部,将运输层报文段中的数据交付到正确的套接字中。
为了完成多路复用与解复用,需要满足:
- 每个套接字有唯一标识符。
- 每个报文段有特殊字段来指示报文段要交付到的套接字。
而上面提到的特殊字段即为 端口号。端口号是一个两字节无符号整数,范围为 0~65535。0~1023 范围的端口号为保留给诸如 HTTP、SMTP 等周知的应用层协议的周知端口号。
有了端口号的概念,我们就可以为每一个套接字分配一个对应的端口号进行标识。传输层实体可以依据端口号决定如何封装数据或将从网络层收到的数据交付给哪个套接字。一般而言,服务器端的进程会显示地确定套接字使用的端口号,而客户端的套接字使用的端口号由运输层实体自动透明地分配。
因此,主机通过 IP 地址 + 端口号的组合便可以将数据发送给合适的套接字。
TCP 与 UDP 的多路复用与解复用的原理有一定差异:
UDP
前面 已经简要介绍了 UDP 与 TCP Socket 维护的内容,下面做一些详细的分析:UDP Socket 维护了一个 (源 IP, 源 Port) 的二元组。而应用程序若想通过 Socket 发送数据,还必须在每次发送前额外附上目标进程的 IP 地址 + 端口号组。UDP 实体收到应用层通过套接字发来的数据与目标地址后,为数据添加包含源端口 + 目标端口信息的头部字段,连同源 IP 与目标 IP向下传递给网络层。网络层收到报文后,再根据一同传下来的源 IP 与目标 IP生成网络层数据报进行传输。
类似的,接收方网络层实体收到数据报后,先拆下网络层头部信息并解析,获知了源 IP 与目标 IP,将这些信息连同传输层数据报向上发送。传输层实体拆下传输层头部信息并解析,获知了源端口与目标端口。传输层实体通过获知的目标 IP 与端口定位到对应的 Socket,并将报文连同发送方地址一同传给应用程序,方便应用程序以该地址作为返回地址发送响应报文。
我们可以发现,由于 UDP Socket 只维护了自身的 IP 地址与端口信息。因此当两个源地址不同的程序向同一个 IP 下的主机的同一个端口发送信息时,接收方实际上将这些信息通过 同一个 Socket 传给了一个程序。
TCP
TCP Socket 存储了一个 (源 IP, 源 Port, 目标 IP, 目标 Port) 的四元组。因此,运输层不再需要应用层显式地提供目标进程的地址。与此同时,由于一个 TCP Socket 由上面提到的四个值共同标识,因此一个主机的一个端口上可以并行运行许多 Socket,每一个 Socket都与一个进程相联系。上面提到的从具有不同源地址的进程向给同一个 IP 下的主机的同一个端口发送的信息将被分解到两个不同的 Socket 上,除非 TCP 报文段携带了关于初始创建连接的请求。关于后者做一些解释:服务器端的应用程序为了接受来自客户端的连接请求需要创建并绑定到该端口上的欢迎套接字。欢迎套接字接收到请求建立连接的报文后,会根据该报文中的 (源 IP, 源 Port, 目标 IP, 目标 Port) 值创建并返回一个连接套接字。
因此 TCP Socket 通过上述四个值便能够区分不同的连接而非 UDP 只能区分不同的目标进程。
此外,当今的应用进程可能采用多线程技术,为每个线程而非独立的进程分配一个 Socket。